﻿// (c) Copyright Microsoft Corporation.
// This source is subject to [###LICENSE_NAME###].
// Please see [###LICENSE_LINK###] for details.
// All other rights reserved.

using System;
using System.Globalization;

namespace EnsureWeb.Controls
{
    /// <summary>
    /// Decade scale of view.
    /// </summary>
    public class DecadeView : TimeView
    {
        /// <summary>
        /// Number of decades.
        /// </summary>
        private static readonly int DecadeCount = 5;

        /// <summary>
        /// Year number in each decades.
        /// </summary>
        internal static readonly int YearsOfDecade = 10;

        /// <summary>
        /// Double decades years.
        /// </summary>
        private static readonly int DoubleDecadeYears = 20;

        /// <summary>
        /// Initializes a new instance of the DecadeView class.
        /// </summary>
        /// <param name="timeline">Parent timeline control.</param>
        public DecadeView(MultiScaleTimeline timeline)
            : base(timeline, TimelineScale.Decade)
        {
        }

        /// <summary>
        /// Gets the display start date.
        /// </summary>
        /// <param name="date">Input date value.</param>
        /// <returns>The display start date.</returns>
        public static DateTime GetDisplayDateStart(DateTime date, YearOfDecade firstYearOfDecade)
        {
            int year = date.Year;
            int firstYear;
            int endNum = Convert.ToInt16(firstYearOfDecade, CultureInfo.InvariantCulture);

            if (year % YearsOfDecade == endNum)
            {
                firstYear = year;
            }
            else if (year % YearsOfDecade > endNum)
            {
                firstYear = year / YearsOfDecade * YearsOfDecade + endNum;
            }
            else
            {
                firstYear = year / YearsOfDecade * YearsOfDecade + endNum - 10;
            }

            firstYear = firstYear - DoubleDecadeYears; // 5 decades

            return new DateTime(firstYear, 1, 1);
        }

        /// <summary>
        /// Gets the start of display date range.
        /// </summary>
        public override DateTime BeginDate
        {
            get
            {
                return DecadeView.GetDisplayDateStart(CurrentDate, this.FirstYearOfDecade);
            }
        }

        /// <summary>
        /// Gets the end of display date range.
        /// </summary>
        public override DateTime EndDate
        {
            get
            {
                int firstYear = BeginDate.Year;
                int endYear = firstYear + YearsOfDecade * DecadeCount - 1;
                return new DateTime(endYear, 12, 31);
            }
        }

        /// <summary>
        /// Gets the number of sub items.
        /// </summary>
        protected override int ItemsCount
        {
            get
            {
                return DecadeCount;
            }
        }

        /// <summary>
        /// Move forward the display date, used when animation out of display.
        /// </summary>
        public override void NextPage()
        {
            UpdateDate(this.BeginDate.AddYears(70));
        }

        /// <summary>
        /// Move backward the display date, used when animation out of display.
        /// </summary>
        public override void PreviousPage()
        {
            UpdateDate(this.BeginDate.AddYears(-30));
        }

        /// <summary>
        /// Gets the next selectable date value.
        /// </summary>
        public override DateTime NextSelectableDate
        {
            get
            {
                return new DateTime(this.SelectedDate.Year + YearsOfDecade, 1, 1);
            }
        }

        /// <summary>
        /// Gets the timeline item text by index.
        /// </summary>
        /// <param name="index">Item index.</param>
        /// <returns>The timeline item text.</returns>
        protected override string GetTimelineItemText(int index)
        {
            long yearStart = (long)this.BeginDate.Year + (long)index * YearsOfDecade;
            long yearEnd = (long)this.BeginDate.Year + ((long)index + 1) * YearsOfDecade - 1;
            return string.Format(CultureInfo.InvariantCulture, "{0} - {1}", yearStart, yearEnd);
        }

        /// <summary>
        /// Gets a value indicating whether the date is selected.
        /// </summary>
        /// <param name="dateTime">The checked date.</param>
        /// <returns>True if the date is selected.</returns>
        public override bool IsDateSelected(DateTime dateTime)
        {
            bool isSel = SelectedDate.Year >= dateTime.Year && SelectedDate.Year <= dateTime.Year + 9;
            return isSel;
        }

        /// <summary>
        /// Check whether the item is selectable.
        /// </summary>
        /// <param name="index">The index of the item.</param>
        /// <returns>If the item is selectable.</returns>
        protected override DateTime GetTimelineItemDate(int index)
        {
            long year = (long)index * YearsOfDecade;

            if (year > int.MaxValue)
            {
                throw new InvalidOperationException("Invalid Cast");
            }

            int intYear = (int)year;
            DateTime itemDate = this.BeginDate.AddYears(intYear);
            return itemDate;
        }

        /// <summary>
        /// Check if a item is selectable.
        /// </summary>
        /// <param name="index">The item index.</param>
        /// <returns>true if the item is selectable.</returns>
        public override bool IsItemSelectable(int index)
        {
            DateTime dateStart = this.GetTimelineItemDate(index);
            DateTime dateEnd = new DateTime(dateStart.Year + 9, 12, 31);

            bool canSel = IsDateRangeSelectable(dateStart, dateEnd);
            return canSel;
        }

        /// <summary>
        /// Gets the rollup the text.
        /// </summary>
        public override string RollupText
        {
            get
            {
                int yearStart = this.BeginDate.Year;
                int yearEnd = yearStart + YearsOfDecade * DecadeCount - 1;
                return yearStart.ToString(CultureInfo.InvariantCulture) + " - " + yearEnd;
            }
        }

        /// <summary>
        /// Gets the rollup date.
        /// </summary>
        protected override DateTime RollupDate
        {
            get
            {
                return DateTime.MinValue;
            }
        }

        /// <summary>
        /// Get the timeline mark position.
        /// </summary>
        /// <param name="date">The timeline mark date.</param>
        /// <param name="timelineWidth">The timeline width.</param>
        /// <returns>Returns the timeline mark position.</returns>
        public override double GetTimelineMarkPosition(DateTime itemDate, double timelineWidth)
        {
            if (IsDateOutOfDisplay(itemDate) != 0)
            {
                throw new ArgumentOutOfRangeException("itemDate", "Argument out of display");
            }

            double markPos;
            DateTime start = this.BeginDate;
            DateTime end = this.EndDate;
            TimeSpan total = end - start;
            TimeSpan markLen = itemDate - start;
            double total_days = total.TotalDays;
            double markLenDays = markLen.TotalDays;
            markPos = markLenDays / total_days * timelineWidth;
            return markPos;
        }
    }
}
